package edu.xhu.behavior.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.org.apache.regexp.internal.RE;
import edu.xhu.api.id.IdClient;
import edu.xhu.behavior.mapper.BiliUserCommentMapper;
import edu.xhu.behavior.service.BiliUserCommentService;
import edu.xhu.model.behavior.dto.AddCommentDto;
import edu.xhu.model.behavior.dto.CommentDto;
import edu.xhu.model.behavior.dto.RootCommentDto;
import edu.xhu.model.behavior.dto.SonCommentDto;
import edu.xhu.model.behavior.enums.CommentStatus;
import edu.xhu.model.behavior.pojos.BiliUserComment;
import edu.xhu.model.common.constants.CommentConstants;
import edu.xhu.model.common.dtos.ResponseResult;
import edu.xhu.model.common.enums.AppHttpCodeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

@Service
@RequiredArgsConstructor
@Slf4j
public class BiliUserCommentServiceImpl extends ServiceImpl<BiliUserCommentMapper, BiliUserComment> implements BiliUserCommentService {

    private final StringRedisTemplate redisTemplate;

    private final BiliUserCommentMapper biliUserCommentMapper;

    private final Executor commentExecutor;

    private final IdClient idClient;

    /**
     * 发表评论
     *
     * @param addCommentDto
     * @return 评论的json
     */
    @Transactional
    @Override
    public ResponseResult<?> addComment(AddCommentDto addCommentDto) {
        if (addCommentDto.getContent() == null || addCommentDto.getContent().length() == 0 || addCommentDto.getContent().length() > 2000)
            return ResponseResult.errorResult(500, "评论内容异常");

        ResponseResult<?> responseResult = null; //用来保存feign之调用结果

        //获取分布式id
        responseResult = idClient.getSnowflakeDistributedId();
        if (!responseResult.getCode().equals(200))
            return ResponseResult.errorResult(500, "获取评论分布式id错误");
        Long commentId = Long.parseLong(responseResult.getData().toString());

        //装配评论的字段
        BiliUserComment commentToInsert = new BiliUserComment();
        commentToInsert.setCommentId(commentId)
                .setVideoId(addCommentDto.getVideoId())
                .setRootId(addCommentDto.getRootId())
                .setParentId(addCommentDto.getParentId())
                .setUserId(addCommentDto.getUserId())
                .setToUserId(addCommentDto.getToUserId())
                .setContent(addCommentDto.getContent())
                .setLove(0)
                .setBad(0)
                .setTotalCommentSize(0)
                .setCreateTime(new Date())
                .setIsDelete(CommentStatus.IS_DELETE_NO.getCode())
                .setIsTop(CommentStatus.IS_TOP_NO.getCode())
                .setIsLike(CommentStatus.IS_LIKE_NO.getCode())
                .setDeep(0);

        //插入数据库
        if (save(commentToInsert) == false)
            return ResponseResult.errorResult(500, "将评论插入数据库错误");
        else {
            //插入成功

            //是子评论，需要刷新对应的根评论的统计数据
            if (commentToInsert.getRootId() != 0L)
                biliUserCommentMapper.increSonCommentCount(commentToInsert.getRootId());

            //返回该评论所对应的json
            return ResponseResult.okResult(JSONUtil.toJsonStr(commentToInsert));
        }
    }

    /**
     * 删除评论
     */
    @Override
    public ResponseResult<?> delComment() {
        return null;
    }


    /**
     * api-按热度或时间返回视频的前limit个根评
     */
    @Override
    public ResponseResult<?> queryRootCommentsByVideoIds(RootCommentDto rootCommentDto) {

        //异常判断，默认返回每个视频最热门的30条评论
        if (rootCommentDto.getPageNo() == null || rootCommentDto.getPageSize() == null || rootCommentDto.getPageNo() <= 0 || rootCommentDto.getPageSize() <= 0)
            rootCommentDto.setPageNo(1).setPageSize(30);

        //开启 rootCommentDto.getVideoIds().size() 个异步任务
        List<CompletableFuture<Void>> completableFutureList = new ArrayList<>();

        //线程安全 list
        List<Map> maps = Collections.synchronizedList(new ArrayList<>());


        for (Long videoId : rootCommentDto.getVideoIds()) {
            completableFutureList.add(CompletableFuture.runAsync(() -> {
//                System.out.println("异步线程开始: " + (System.currentTimeMillis() - startTime) + " 毫秒");

                Boolean sortByHotness = true; //根评论排序类型·
                if (rootCommentDto.getSortType().equals(CommentConstants.ROOT_COMMENT_SORT_BY_TIME))
                    sortByHotness = false;

                JSONArray jsonArray = JSONUtil.parseArray(biliUserCommentMapper.queryRootCommentsByVideoIds(
                        videoId,
                        rootCommentDto.getLoveWeight(),
                        rootCommentDto.getCommentWeight(),
                        (rootCommentDto.getPageNo() - 1) * rootCommentDto.getPageSize(),
                        rootCommentDto.getPageSize(),
                        sortByHotness));

                List<Map> list = JSONUtil.toList(jsonArray, Map.class);

                maps.addAll(list);

//                System.out.println("异步线程结束: " + (System.currentTimeMillis() - startTime) + " 毫秒");

            }, commentExecutor));
        }


        completableFutureList.forEach(item -> {
            item.join();
        });


        if (maps == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        return ResponseResult.okResult(JSONUtil.toJsonStr(maps));
    }

    /**
     * 根据视频id(一条)，返回该视频所有根评论的id以及相应的热度值，(热度/时间排序)
     *
     * @param rootCommentDto
     */
    @Override
    public ResponseResult<?> queryRootCommentIdsByVideoId(RootCommentDto rootCommentDto) {
        if (rootCommentDto.getVideoIds() == null || rootCommentDto.getVideoIds().size() == 0)
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "videoId为空");

        if (rootCommentDto.getVideoIds().size() > 1)
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "videoId个数大于1");

        Boolean sortByHotness = true; //根评论排序类型·
        if (rootCommentDto.getSortType().equals(CommentConstants.ROOT_COMMENT_SORT_BY_TIME))
            sortByHotness = false;

        List<Map<String, Object>> mapList = biliUserCommentMapper.queryRootCommentIdsByVideoId(
                rootCommentDto.getVideoIds().get(0),
                rootCommentDto.getLoveWeight(),
                rootCommentDto.getCommentWeight(),
                sortByHotness);

        return ResponseResult.okResult(JSONUtil.toJsonStr(mapList));
    }

    /**
     * api-根据评论id返回相应的评论
     *
     * @param rootCommentDto
     * @return
     */
    @Override
    public ResponseResult<?> queryRootCommentsByCommentIds(RootCommentDto rootCommentDto) {
        if (rootCommentDto.getCommentIds() == null || rootCommentDto.getCommentIds().size() == 0)
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "commentIds为空");

        List<Map<String, Object>> mapList = biliUserCommentMapper.queryRootCommentsByCommentIds(
                rootCommentDto.getCommentIds(),
                rootCommentDto.getLoveWeight(),
                rootCommentDto.getCommentWeight());

        if (mapList == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        return ResponseResult.okResult(JSONUtil.toJsonStr(mapList));
    }


    /**
     * api-返回根评的所有子评
     */
    @Override
    public ResponseResult<?> querySonCommentsByRootIds(SonCommentDto sonCommentDto) {
        if (sonCommentDto.getRootCommentIds() == null || sonCommentDto.getRootCommentIds().size() == 0)
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "rootCommentIds为空");

        List<Map<String, Object>> mapList = biliUserCommentMapper.querySonCommentsByRootIds(sonCommentDto.getRootCommentIds());
        if (mapList == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        return ResponseResult.okResult(JSONUtil.toJsonStr(mapList));
    }
}
